﻿using System.Collections.Generic;
using XNAFight.Characters.Core;
using XNAFight.Engine;

namespace XNAFight.Characters.Core
{
    public class MovesInterpreter
    {        
        // Fixe la limite du buffer pour verifier les dashs
        private static int dash_buffer_depth = 15;

        // FILTRAGE VIA LE BUFFER
        public static List<BMoveSequence> getMovesFromBuffer(List<BMoveSequence> _sequences, List<List<BMove>> _buffer)
        {
            // On liste tous les moves qui pourraient etre declenchés
            List<BMoveSequence> triggerred_moves = new List<BMoveSequence>();

            for (int i = 0; i < _sequences.Count; i++)
            {
                if (isMoveTriggered(_sequences[i], _buffer))
                    triggerred_moves.Add(_sequences[i]);
            }

            return triggerred_moves;
        }
        private static bool isMoveTriggered(BMoveSequence _bmoves, List<List<BMove>> _buffer)
        {
            //on regarde si le(s) dernier(s) coup(s) du move est/sont present(s) dans la frame la plus recente du buffer
            int last_index = _bmoves.BasicMoves.Count - 1;

            bool lastBMoveOK = true;
            
            int i = 0;
            while (i < _bmoves.BasicMoves[last_index].Count && lastBMoveOK)
            {
                if (getMoveIndexInBufferFrom(_bmoves.BasicMoves[last_index][i], 0, _buffer) != 0)
                    lastBMoveOK = false;

                i++;
            }

            if (!lastBMoveOK)
                return false;

            bool allBMovesOk = true;
            int previousIndex = 0;

            // On regarde si les autres bmoves du move sont presents dans l'ordre
            i = last_index-1;
            while (i >= 0 && allBMovesOk)
            {
                int index = getMoveIndexInBufferFrom(_bmoves.BasicMoves[i][0], previousIndex, _buffer);

                if (index == -1)
                    allBMovesOk = false;

                previousIndex = index;

                int j = 1;
                while (j < _bmoves.BasicMoves[i].Count && allBMovesOk)
                {
                    index = getMoveIndexInBufferFrom(_bmoves.BasicMoves[i][j], previousIndex, _buffer);

                    if (index != previousIndex)
                        allBMovesOk = false;

                    j++;
                }

                i--;
            }

            return allBMovesOk;
        }
        private static int getMoveIndexInBufferFrom(BMove _bmove, int _start_index, List<List<BMove>> _buffer)
        {
            int i = _start_index;
            bool found = false;

            while (i < _buffer.Count && !found)
            {
                int j = 0;
                while (j < _buffer[i].Count && !found)
                {
                    if (_buffer[i][j] == _bmove)
                        found = true;
                    else
                        j++;
                }
                if (!found)
                    i++;
            }

            if (!found)
                return -1;

            return i;
        }

        // FILTRAGE VIA LES FLAGS
        public static List<BMoveSequence> getMovesFromFlags(List<BMoveSequence> _sequences, PositionVerticale _pos_verticale)
        {
            // On copie toute la liste
            List<BMoveSequence> ok_moves = new List<BMoveSequence>();
            for (int index = 0; index < _sequences.Count; index++)
            {
                ok_moves.Add(_sequences[index]);
            }

            // On retire de la copie tous les mouvements dont les flags ne sont pas compatibles
            #region PositionVerticale
            int i = 0;
            while(i < ok_moves.Count)
            {
                if (!ok_moves[i].Coup.Air && _pos_verticale == PositionVerticale.AIR)
                {
                    ok_moves.RemoveAt(i);
                }
                else if (!ok_moves[i].Coup.Stand && _pos_verticale == PositionVerticale.STAND)
                {
                    ok_moves.RemoveAt(i);
                }
                else if (!ok_moves[i].Coup.Crouch && _pos_verticale == PositionVerticale.CROUCH)
                {
                    ok_moves.RemoveAt(i);
                }
                else
                {
                    i++;
                }
            }
            #endregion

            return ok_moves;
        }

        // FILTRAGE VIA LES PRIORITES
        public static BMoveSequence getPriorityMove(List<BMoveSequence> _sequences)
        {
            // On copie toute la liste
            List<BMoveSequence> ok_moves = new List<BMoveSequence>();
            for (int index = 0; index < _sequences.Count; index++)
            {
                ok_moves.Add(_sequences[index]);
            }

            // On ne garde que les elements de priorité la plus haute
            while (ok_moves.Count > 1)
            {
                if (ok_moves[1].Coup.Priorite > ok_moves[0].Coup.Priorite)
                {
                    ok_moves.RemoveAt(0);
                }
                else
                {
                    ok_moves.RemoveAt(1);
                }
            }
            if (ok_moves.Count > 0)
                return ok_moves[0];

            return null;
        }

        // DETECTION DES DASHS
        public static bool isDashingForward(List<List<BMove>> _buffer)
        {
            if (_buffer.Count < 3)
                return false;

            bool forward = false;
            int i = 0;
            while (!forward && i < _buffer[0].Count)
            {
                if (_buffer[0][i] == BMove.FORWARD)
                    forward = true;
                i++;
            }

            if (!forward)
                return false;

            bool interval_ok = false;

            if (_buffer[1].Count == 0)
                interval_ok = true;

            i = 0;
            while (!interval_ok && i < _buffer[1].Count)
            {
                if (_buffer[1][i] != BMove.FORWARD 
                    && _buffer[1][i] != BMove.DOWN_FORWARD 
                    && _buffer[1][i] != BMove.DOWN 
                    && _buffer[1][i] != BMove.DOWN_BACK)
                    interval_ok = true;
                i++;
            }

            if (!interval_ok)
                return false;

            forward = false;
            i = 2;
            while (!forward && i < _buffer.Count && i < dash_buffer_depth)
            {
                int j = 0;
                while (!forward && j < _buffer[i].Count)
                {
                    if (_buffer[i][j] == BMove.FORWARD)
                        forward = true;
                    j++;
                }
                i++;
            }

            if (!forward)
                return false;

            if (i >= _buffer.Count)
                return false;

            interval_ok = false;


            while (!interval_ok && i < _buffer.Count && i < dash_buffer_depth)
            {
                if (_buffer[i].Count == 0)
                    interval_ok = true;

                int j = 0;
                while (!interval_ok && j < _buffer[i].Count)
                {
                    if (_buffer[i][j] != BMove.FORWARD
                        && _buffer[i][j] != BMove.DOWN_FORWARD
                        && _buffer[i][j] != BMove.DOWN
                        && _buffer[i][j] != BMove.DOWN_BACK)
                        interval_ok = true;
                    j++;
                }
                i++;
            }

            return interval_ok;
        }
        public static bool isDashingBackward(List<List<BMove>> _buffer)
        {
            if (_buffer.Count < 3)
                return false;

            bool backward = false;
            int i = 0;
            while (!backward && i < _buffer[0].Count)
            {
                if (_buffer[0][i] == BMove.BACK)
                    backward = true;
                i++;
            }

            if (!backward)
                return false;

            bool interval_ok = false;

            if (_buffer[1].Count == 0)
                interval_ok = true;

            i = 0;
            while (!interval_ok && i < _buffer[1].Count)
            {
                if (_buffer[1][i] != BMove.BACK
                    && _buffer[1][i] != BMove.DOWN_FORWARD
                    && _buffer[1][i] != BMove.DOWN
                    && _buffer[1][i] != BMove.DOWN_BACK)
                    interval_ok = true;
                i++;
            }

            if (!interval_ok)
                return false;

            backward = false;
            i = 2;
            while (!backward && i < _buffer.Count && i < dash_buffer_depth)
            {
                int j = 0;
                while (!backward && j < _buffer[i].Count)
                {
                    if (_buffer[i][j] == BMove.BACK)
                        backward = true;
                    j++;
                }
                i++;
            }

            if (!backward)
                return false;

            if (i >= _buffer.Count)
                return false;

            interval_ok = false;


            while (!interval_ok && i < _buffer.Count && i < dash_buffer_depth)
            {
                if (_buffer[i].Count == 0)
                    interval_ok = true;

                int j = 0;
                while (!interval_ok && j < _buffer[i].Count)
                {
                    if (_buffer[i][j] != BMove.BACK
                        && _buffer[i][j] != BMove.DOWN_FORWARD
                        && _buffer[i][j] != BMove.DOWN
                        && _buffer[i][j] != BMove.DOWN_BACK)
                        interval_ok = true;
                    j++;
                }
                i++;
            }

            return interval_ok;
        }
    }
}
